<?php

declare(strict_types=1);

namespace App\Common\Service;

use App\Setting\Service\SettingConfigService;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Hyperf\Codec\Packer\JsonPacker;
use Hyperf\Contract\PackerInterface;
use Hyperf\Coroutine\Coroutine;
use Hyperf\Guzzle\CoroutineHandler;
use Mine\Abstracts\AbstractService;
use Mine\Exception\NormalStatusException;
use Psr\Container\ContainerInterface;
use Psr\SimpleCache\CacheInterface;

/**
 * 短链云服务
 */
class ShortChainService extends AbstractService
{
    protected Client $client;

    protected PackerInterface $packer;

    protected string $baseUri = 'https://api.wai.cn';

    protected string $appid = '9b5f35c6c6';

    protected string $secret = 'NWFmNWQ4NzU0Y2QwZDc2ZTQ2YmMxYjk3YzRlMTA2ZTMzZWUyY2VkOTJhYjhmMDJhZDU3M2UxOTJhYTNlOWZkNQ==';

    protected string $signVer = '1.0';

    protected string $accessTokenKey = 'ch_short_chain_access_token';

    protected ContainerInterface $container;

    protected CacheInterface $cache;

    public function __construct(ContainerInterface $container,CacheInterface $cache,PackerInterface $packer = null)
    {
        $handler = null;
        if (Coroutine::inCoroutine()) {
            $handler = new CoroutineHandler();
        }

        $this->client = new Client([
            'base_uri' => $this->baseUri,
            'timeout' => 3,
            'handler' => $handler,
        ]);
        $this->packer = $packer ?? new JsonPacker();
        $this->container = $container;
        $this->cache = $cache;
    }

    /**
     * 获取接口凭证
     * @return mixed
     */
    public function getAccessToken(): mixed
    {
        $accessToken = $this->cache->get($this->accessTokenKey);
        if(!empty($accessToken)){
            return $accessToken;
        }
        $sign = $this->generateSign();

        $params = [
            'app_id' => $this->appid,
            'signature' => $sign,
            'timestamp' => time()
        ];

        $response = $this->post('/api/v1/getAccessToken',$params);
        $accessToken = $response['access_token'];
        $accessToken && $this->cache->set($this->accessTokenKey,$accessToken,7000);
        return $accessToken;
    }


    /**
     * 创建短链
     * @param string $url
     * @param string $validTime 短链过期时间 空则代表永久 2022-01-01 00:00:00
     * @param int $needDecrypt url是否需要解密 0-否 1-是
     * @return mixed
     */
    public function createChains(string $url,string $validTime = '',int $needDecrypt = 0): mixed
    {
        return $this->post('/api/v1/chains.create?access_token='.$this->getAccessToken(),[
            'target_url' => $url,
            'valid_time' => $validTime,
            'need_decrypt' => $needDecrypt
        ]);
    }

    /**
     * 更新短链
     * @param string $chainCode
     * @param string $url
     * @return mixed
     */
    public function updateChains(string $chainCode,string $url): mixed
    {
        return $this->post('/api/v1/chains.update?access_token='.$this->getAccessToken(),[
            'target_url' => $url,
            'chain_code' => $chainCode
        ]);
    }

    /**
     * 删除短链
     * @param $chainCode
     * @return bool
     */
    public function delChains($chainCode): bool
    {
        $this->post('/api/v1/chains.del?access_token='.$this->getAccessToken(),[
            'chain_code' => [
                $chainCode
            ]
        ]);
        return true;
    }

    private function generateSign()
    {
        $data = [
            'app_id' => $this->appid,
            'app_secret' => $this->secret,
            'sign_ver' => $this->signVer,
            'timestamp' => time()
        ];
        krsort($data);
        $str = http_build_query($data);
        return md5($str);
    }

    private function post(string $uri, array $params)
    {
        try {
            $response = $this->client->post($uri, [
                'json' => $params
            ]);
            $data = $this->packer->unpack((string) $response->getBody());
            if(!empty($data) && $data['success']){
                return $data['data'];
            }else{
                throw new NormalStatusException('短链生成失败'.$data['message']);
            }
        } catch (GuzzleException $e) {
            throw new NormalStatusException('请求失败'.$e->getMessage());
        }
    }
}